#include "drv_rgb_led.h"

/**********************************************************
 *  Data type
**********************************************************/
typedef struct {
  uint8_t r;
  uint8_t g;
  uint8_t b;
}RGBColorType;

typedef struct {
  RGBColorType color;
  RGBColorType color_tmp;
}RGBColorStateType;

typedef struct {
  uint16_t distance_mm;
  RGBColorType color;
}DistanceColorType;

typedef struct {
    int PwmCH_R;
    int PwmCH_G;
    int PwmCH_B;
    float dimAdjust; /*Range 0.1~1.0*/
    
    uint8_t bIsEnableSlowTransfer:1;
    uint8_t transferRate:4;
}RGBHwConfigType;

/**********************************************************
 *  Macro define
**********************************************************/
#define SET_PWM_LED_DIM(ch,c)   \
  bsp_pwm_set_duty( ch, (((float)c)/255.0f) )

#define SET_RGB_LED_COLOR(hwCfg,color)    \
    SET_PWM_LED_DIM(hwCfg.PwmCH_R,hwCfg.dimAdjust*color.r);\
    SET_PWM_LED_DIM(hwCfg.PwmCH_G,hwCfg.dimAdjust*color.g);\
    SET_PWM_LED_DIM(hwCfg.PwmCH_B,hwCfg.dimAdjust*color.b)

#define RGB(d)   .color={(d>>16)&0xFF,(d>>8)&0xFF,(d&0xFF)}

/**********************************************************
 *  Constant
**********************************************************/
static const RGBHwConfigType RGBHwConfig[MAX_RGB_LED_NUM]={
    {
        PWM_CH_LED0_R,PWM_CH_LED0_G,PWM_CH_LED0_B,
        0.7f,   1,  7,
    },
};

static const DistanceColorType g_ColorTable[]={
  {50,  RGB(0xFF0000)},     /* within 5cm */
  {100, RGB(0xFF0089)},     /* within 10cm */
  {150, RGB(0xFF0089)},
  {200, RGB(0xEF00FF)},
  {300, RGB(0xFF8000)},
  {400, RGB(0xFFE600)},
  {500, RGB(0x9AFF00)},
  {650, RGB(0x00FF11)},
  {800, RGB(0x00FFD5)},
  {1000, RGB(0x00A2FF)},
  {1200, RGB(0x1100FF)},
  {0xFFFF,RGB(0xA0A0A0)},    /*Max*/
};

/**********************************************************
 *  Local var
**********************************************************/
RGBColorStateType RGBLedState[MAX_RGB_LED_NUM];

/**********************************************************
 *  API
**********************************************************/
static void drv_rgb_led_TransferColor(void)
{
    float f_diff;

    #define COLOR_DIFF(state,c,rate) \
        f_diff = (float)((int)state.color.c - (int)state.color_tmp.c);\
        f_diff /= rate ;\
        state.color_tmp.c += (int)f_diff

    for(int i=0;i<MAX_RGB_LED_NUM;i++){
        if(RGBHwConfig[i].bIsEnableSlowTransfer == 1){
            COLOR_DIFF(RGBLedState[i],r,RGBHwConfig[i].transferRate+1);
            COLOR_DIFF(RGBLedState[i],g,RGBHwConfig[i].transferRate+1);
            COLOR_DIFF(RGBLedState[i],b,RGBHwConfig[i].transferRate+1);
            
            SET_RGB_LED_COLOR(RGBHwConfig[i],RGBLedState[i].color_tmp);
        }
    }
}

void drv_rgb_led_SetColorByDistance(int RGBChannel,int distance)
{
  /*distance is mm unit*/
  for(int i=0;i<sizeof(g_ColorTable);i++){
    if(distance<g_ColorTable[i].distance_mm){
        RGBLedState[RGBChannel].color = g_ColorTable[i].color;
        if(RGBHwConfig[RGBChannel].bIsEnableSlowTransfer == 0){
            SET_RGB_LED_COLOR(RGBHwConfig[RGBChannel],RGBLedState[RGBChannel].color);
        }
        break;
    }
  }
}

void drv_rgb_led_SetColor(int RGBChannel,uint8_t r,uint8_t g,uint8_t b)
{
    RGBLedState[RGBChannel].color.r=r;
    RGBLedState[RGBChannel].color.g=g;
    RGBLedState[RGBChannel].color.b=b;
    if(RGBHwConfig[RGBChannel].bIsEnableSlowTransfer == 0){
        SET_RGB_LED_COLOR(RGBHwConfig[RGBChannel],RGBLedState[RGBChannel].color);
    }
}

void drv_rgb_led_main_function(void)
{
  static uint32_t tick_ms=0;

  tick_ms++;
  if(tick_ms>=100){
    tick_ms=0;
    drv_rgb_led_TransferColor();
  }

}